

    avalon.define = function(name, factory) {
        var args = avalon.slice(arguments)
        if (typeof name !== "string") {
            name = generateID()
            args.unshift(name)
        }
        if (Array.isArray(args[1])) { //向前兼容
            args.splice(1, 1)
        }
        if (typeof args[1] !== "function") {
            avalon.error("factory必须是函数")
        }
        factory = args[1]
        var scope = {
            $watch: noop
        }
        factory(scope) //得到所有定义
        var model = modelFactory(scope) //偷天换日，将scope换为model
        stopRepeatAssign = true
        factory(model)
        stopRepeatAssign = false
        model.$id = name
        return VMODELS[name] = model
    }
    var Observable = {
        $watch: function(type, callback) {
            var callbacks = this.$events[type]
            if (callbacks) {
                callbacks.push(callback)
            } else {
                this.$events[type] = [callback]
            }
            return this
        },
        $unwatch: function(type, callback) {
            var n = arguments.length
            if (n === 0) {
                this.$events = {}
            } else if (n === 1) {
                this.$events[type] = []
            } else {
                var callbacks = this.$events[type] || []
                var i = callbacks.length
                while (--i > -1) {
                    if (callbacks[i] === callback) {
                        return callbacks.splice(i, 1)
                    }
                }
            }
            return this
        },
        $fire: function(type) {
            var callbacks = this.$events[type] || [] //防止影响原数组
            var all = this.$events.$all || []
            var args = [].slice.call(arguments, 1)
            for (var i = 0, callback; callback = callbacks[i++]; ) {
                callback.apply(this, args)
            }
            for (var i = 0, callback; callback = all[i++]; ) {
                callback.apply(this, args)
            }
        }
    }

    function updateViewModel(a, b, isArray) {
        if (isArray) {
            var an = a.length,
                    bn = b.length
            if (an > bn) {
                a.splice(bn, an - bn)
            } else if (bn > an) {
                a.push.apply(a, b.slice(an))
            }
            var n = Math.min(an, bn)
            for (var i = 0; i < n; i++) {
                a.set(i, b[i])
            }
        } else {
            for (var i in b) {
                if (b.hasOwnProperty(i) && a.hasOwnProperty(i) && i !== "$id") {
                    a[i] = b[i]
                }
            }
        }
    }
    var systemOne = avalon.oneObject("$index,$remove,$first,$last")
    var watchOne = avalon.oneObject("$id,$skipArray,$watch,$unwatch,$fire,$events,$json,$model")

    function modelFactory(scope, model, isArray) {
        if (isArray) {
            return Collection(scope)
        }
        var skipArray = scope.$skipArray, //要忽略监控的属性名列表
                vmodel = {},
                Descriptions = {}, //内部用于转换的对象
                callSetters = [],
                callGetters = [],
                VBPublics = Object.keys(watchOne) //用于IE6-8
        model = model || {}
        skipArray = Array.isArray(skipArray) ? skipArray.concat(VBPublics) : VBPublics

        function loop(name, value) {
            if (!watchOne[name]) {
                model[name] = value
            }
            var valueType = getType(value)
            if (valueType === "function") {
                VBPublics.push(name) //函数无需要转换
            } else {
                if (skipArray.indexOf(name) !== -1) {
                    return VBPublics.push(name)
                }
                if (name.charAt(0) === "$" && !systemOne[name]) {
                    return VBPublics.push(name)
                }
                var accessor, oldArgs
                if (valueType === "object" && typeof value.get === "function" && Object.keys(value).length <= 2) {
                    var setter = value.set,
                            getter = value.get
                    accessor = function(neo) { //创建计算属性
                        if (arguments.length) {
                            if (stopRepeatAssign) {
                                return //阻止重复赋值
                            }
                            if (typeof setter === "function") {
                                setter.call(vmodel, neo)
                            }
                            if (oldArgs !== neo) { //由于VBS对象不能用Object.prototype.toString来判定类型，我们就不做严密的检测
                                oldArgs = neo
                                notifySubscribers(accessor) //通知顶层改变
                                vmodel.$events && vmodel.$fire(name, neo, value)
                            }
                        } else {
                            if (openComputedCollect || !accessor.locked) {
                                collectSubscribers(accessor)
                            }
                            return value = model[name] = getter.call(vmodel) //保存新值到model[name]
                        }
                    }
                    accessor.nick = name
                    callGetters.push(accessor)
                } else {
                    value = NaN
                    callSetters.push(name)
                    accessor = function(neo) { //创建监控属性或数组
                        if (arguments.length) {
                            if (stopRepeatAssign) {
                                return //阻止重复赋值
                            }
                            if (value !== neo) {
                                var old = value
                                if (valueType === "array" || valueType === "object") {
                                    if (value && value.$id) {
                                        updateViewModel(value, neo, Array.isArray(neo))
                                    } else if (Array.isArray(neo)) {
                                        value = Collection(neo, vmodel, name)
                                    } else {
                                        value = modelFactory(neo, neo)
                                    }
                                } else {
                                    value = neo
                                }
                                model[name] = value && value.$id ? value.$model : value
                                notifySubscribers(accessor) //通知顶层改变
                                vmodel.$events && vmodel.$fire(name, value, old)
                            }
                        } else {
                            collectSubscribers(accessor) //收集视图函数
                            return value
                        }
                    }
                }
                accessor[subscribers] = []
                Descriptions[name] = {
                    set: accessor,
                    get: accessor,
                    enumerable: true
                }
            }
        }
        for (var i in scope) {
            loop(i, scope[i])
        }

        vmodel = defineProperties(vmodel, Descriptions, VBPublics)
        VBPublics.forEach(function(name) {
            if (!watchOne[name]) {
                vmodel[name] = scope[name]
            }
        })
        callSetters.forEach(function(prop) {
            vmodel[prop] = scope[prop] //为空对象赋值
        })
        callGetters.forEach(function(fn) {
            Publish[expose] = fn
            callSetters = vmodel[fn.nick]
            fn.locked = 1
            delete Publish[expose]
        })
        vmodel.$model = vmodel.$json = model
        vmodel.$events = {} //VB对象的方法里的this并不指向自身，需要使用bind处理一下
        vmodel.$watch = Observable.$watch.bind(vmodel)
        vmodel.$unwatch = Observable.$unwatch.bind(vmodel)
        vmodel.$fire = Observable.$fire.bind(vmodel)
        vmodel.$id = generateID()
        vmodel.hasOwnProperty = function(name) {
            return name in vmodel.$model
        }
        return vmodel
    }
    var defineProperty = Object.defineProperty
    try {
        defineProperty({}, "_", {
            value: "x"
        })
        var defineProperties = Object.defineProperties
    } catch (e) {
        if ("__defineGetter__" in avalon) {
            defineProperty = function(obj, prop, desc) {
                if ('value' in desc) {
                    obj[prop] = desc.value
                }
                if ('get' in desc) {
                    obj.__defineGetter__(prop, desc.get)
                }
                if ('set' in desc) {
                    obj.__defineSetter__(prop, desc.set)
                }
                return obj
            }
            defineProperties = function(obj, descs) {
                for (var prop in descs) {
                    if (descs.hasOwnProperty(prop)) {
                        defineProperty(obj, prop, descs[prop])
                    }
                }
                return obj
            }
        }
    }
    if (!defineProperties && window.VBArray) {
        window.execScript([
            "Function parseVB(code)",
            "\tExecuteGlobal(code)",
            "End Function"
        ].join("\n"), "VBScript")

        function VBMediator(description, name, value) {
            var fn = description[name] && description[name].set
            if (arguments.length === 3) {
                fn(value)
            } else {
                return fn()
            }
        }
        defineProperties = function(publics, description, array) {
            publics = array.slice(0)
            publics.push("hasOwnProperty")
            var className = "VBClass" + setTimeout("1"),
                    owner = {}, buffer = []
            buffer.push(
                    "Class " + className,
                    "\tPrivate [__data__], [__proxy__]",
                    "\tPublic Default Function [__const__](d, p)",
                    "\t\tSet [__data__] = d: set [__proxy__] = p",
                    "\t\tSet [__const__] = Me", //链式调用
                    "\tEnd Function")
            publics.forEach(function(name) { //添加公共属性,如果此时不加以后就没机会了
                if (owner[name] !== true) {
                    owner[name] = true //因为VBScript对象不能像JS那样随意增删属性
                    buffer.push("\tPublic [" + name + "]") //你可以预先放到skipArray中
                }
            })
            for (var name in description) {
                owner[name] = true
                buffer.push(
                        //由于不知对方会传入什么,因此set, let都用上
                        "\tPublic Property Let [" + name + "](val)", //setter
                        "\t\tCall [__proxy__]([__data__], \"" + name + "\", val)",
                        "\tEnd Property",
                        "\tPublic Property Set [" + name + "](val)", //setter
                        "\t\tCall [__proxy__]([__data__], \"" + name + "\", val)",
                        "\tEnd Property",
                        "\tPublic Property Get [" + name + "]", //getter
                        "\tOn Error Resume Next", //必须优先使用set语句,否则它会误将数组当字符串返回
                        "\t\tSet[" + name + "] = [__proxy__]([__data__],\"" + name + "\")",
                        "\tIf Err.Number <> 0 Then",
                        "\t\t[" + name + "] = [__proxy__]([__data__],\"" + name + "\")",
                        "\tEnd If",
                        "\tOn Error Goto 0",
                        "\tEnd Property")
            }
            buffer.push("End Class") //类定义完毕
            buffer.push(
                    "Function " + className + "Factory(a, b)", //创建实例并传入两个关键的参数
                    "\tDim o",
                    "\tSet o = (New " + className + ")(a, b)",
                    "\tSet " + className + "Factory = o",
                    "End Function")
            window.parseVB(buffer.join("\r\n"))

            var model = window[className + "Factory"](description, VBMediator)
            return model
        }
    }

    function collectSubscribers(accessor) { //收集依赖于这个访问器的订阅者
        if (Publish[expose]) {
            var list = accessor[subscribers]
            list && avalon.Array.ensure(list, Publish[expose]) //只有数组不存在此元素才push进去
        }
    }

    function notifySubscribers(accessor, el) { //通知依赖于这个访问器的订阅者更新自身
        var list = accessor[subscribers]
        if (list && list.length) {
            var args = [].slice.call(arguments, 1)
            var safelist = list.concat()
            for (var i = 0, fn; fn = safelist[i++]; ) {
                el = fn.element
                if (el && (!el.noRemove) && (el.sourceIndex === 0 || el.parentNode === null)) {
                    avalon.Array.remove(list, fn)
                    log(fn + "")
                } else {
                    fn.apply(0, args) //强制重新计算自身
                }
            }
        }
    }
    